package com.aliang.shopping.log.aspect;


import com.aliang.shopping.contact.SqlColumnConstant;
import com.aliang.shopping.log.annotation.LogLogin;
import com.aliang.shopping.log.enums.LoginType;
import com.aliang.shopping.model.po.LoginLog;
import com.aliang.shopping.service.LoginLogService;
import com.aliang.shopping.util.RequestUtil;
import lombok.AllArgsConstructor;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 操作日志记录处理
 */
@Aspect
@Component
@AllArgsConstructor
public class LoginLogAspect {
    private final RequestUtil requestUtil;
    private final LoginLogService loginLogService;

    /**
     * 正常处理完毕，记录日志
     *
     * @param joinPoint 切点
     */
    @AfterReturning(pointcut = "@annotation(logLogin)")
    public void doAfterReturning(JoinPoint joinPoint, LogLogin logLogin) {
        handleLoginLog(joinPoint, logLogin, null);
    }

    /**
     * 抛出异常后，记录日志
     *
     * @param joinPoint 切点
     * @param e         异常
     */
    @AfterThrowing(value = "@annotation(logLogin)", throwing = "e")
    public void doAfterThrowing(JoinPoint joinPoint, LogLogin logLogin, Exception e) {
        handleLoginLog(joinPoint, logLogin, e);
    }

    /**
     * 处理日志
     *
     * @param joinPoint
     * @param logLogin
     * @param e
     */
    protected void handleLoginLog(final JoinPoint joinPoint, LogLogin logLogin, final Exception e) {
        //通过上下文环境，获取请求对象
        RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
        HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
        //获取IP地址
        String clientIP = this.requestUtil.getClientIP(request);
        // 获取IP来源
        String ipSource = this.requestUtil.getRegion(clientIP);
        //获取UA信息
        RequestUtil.UA ua = this.requestUtil.getUa(request);
        //获取登录方式
        LoginType loginType = logLogin.loginType();
        //获取请求参数
        String arg = joinPoint.getArgs()[0].toString();
        //获取各个字段的键值对
        Map<String, String> dtoInfo = getDTOInfo(arg);

        if (arg.contains(SqlColumnConstant.USERNAME)) {
            arg = dtoInfo.get(SqlColumnConstant.USERNAME);
        } else if (arg.contains(SqlColumnConstant.EMAIL)) {
            arg = dtoInfo.get(SqlColumnConstant.EMAIL);
        } else if (arg.contains(SqlColumnConstant.PHONE)) {
            arg = dtoInfo.get(SqlColumnConstant.PHONE);
        } else {
            arg = "未知";
        }

        //新建登录日志对象
        LoginLog loginLog = LoginLog.builder()
                .keyword(arg)
                .loginMethod(loginType.getDesc())
                .os(ua.getOs())
                .browser(ua.getBrowser())
                .loginIp(clientIP)
                .ipRegion(ipSource)
                .build();
        //判断是否成功
        if (Objects.nonNull(e)) {
            //写入错误信息
            loginLog.setErrorMsg(e.getMessage());
            //设置状态为失败
            loginLog.setStatus(SqlColumnConstant.STATUS_FAIL);
        }
        // 存入数据库
        loginLogService.save(loginLog);
    }

    public Map<String, String> getDTOInfo(String args) {
        String[] split = args.split("\\(")[1].split("\\)")[0].split(",");
        return Arrays.stream(split).map(s -> s.split("=")).collect(Collectors.toMap(s -> s[0], s -> s[1]));
    }
}